package UIUtils {
	import UIFree.ObjectEvent;
	import UIFree.uif_app;
	
	import flash.display.DisplayObject;
	import flash.display.GradientType;
	import flash.display.Graphics;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.system.ApplicationDomain;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.utils.Timer;
	
	public class uif_util extends Object {
		
		public static const mlsPerMinute:int = 1000 * 60; 
		public static const mlsPerHour:int = 1000 * 60 * 60; 
		public static const mlsPerDay:int = 1000 * 60 * 60 * 24;
		public static const RBTRI: Number = 1.4142135623730950488016887242097;
		public static const SLASH: String = '/';
		
		public static const NULLPOINT: Point = new Point(0, 0);
		
		public static const emptyEventFunc: Function = function(e: Event): void {
		}
		
		public static function decline(num: Number, word: String): String {
	        var n:String = Math.floor(num).toString() + " ", p:Array = word.split(/-|,/g);
	        var pn: int = n.match(/([^1]|^)1 /) ? 1 : (n.match(/([^1]|^)[234] /) ? 2 : 3);
	        return n + p[0] + p[pn];
/*	        var n: String = Math.floor(num).toString();
	        var p:Array = word.split(/-|,/g);
	        var pn: int = n.match(/([^1]|^)1 /) ? 1 : (n.match(/([^1]|^)[234] /) ? 2 : 3);
	        return num.toString() + p[0] + p[pn];*/
	    }
	    
		public static function EnterHere(inner	: Rectangle, size: Point, toInner: Boolean=true): Rectangle {
			var scale	: Point = new Point(inner.width / size.x, inner.height / size.y);
			var result  : Rectangle = new Rectangle();
			if ((scale.x < 1) || (scale.y < 1)) {
				var r: Number;
				if (toInner) r = scale.x<scale.y?scale.x:scale.y;
				else r = scale.x>scale.y?scale.x:scale.y;
				result.width = size.x * r;
				result.height = size.y * r;
			} else {
				result.width = size.x;
				result.height = size.y;
			}
			
			result.x = inner.x + (inner.width - result.width) / 2;
			result.y = inner.y + (inner.height - result.height) / 2;
			return result;
		}
		
		public static function correctPosition(inner: Rectangle, bounce: Rectangle): Rectangle {
			
			var rect: Rectangle = bounce.clone();
			if (bounce.x >= inner.x) {
				if (bounce.x + bounce.width > inner.x + inner.width)
					rect.x = (inner.x + inner.width) - bounce.width; 
			} else if (bounce.x < inner.x) rect.x = inner.x;

			if (bounce.y >= inner.y) {
				if (bounce.y + bounce.height > inner.y + inner.height)
					rect.y = (inner.y + inner.height) - bounce.height; 
			} else if (bounce.y < inner.y) rect.y = inner.y;
			
			return rect;
		}
		
	    public static function timeToStr(sec: int, ver: Number=0): String {
	    	var vars: Array = [
	    		{h:'ча-с,са,сов', m:'мину-та,ты,т', s:'секун-да,ды,д'},
	    		{h:'ча-с,са,сов', m:'мину-ту,ты,т', s:'секун-ду,ды,д'}
	    	]
	    	var s: int = sec % 60;
	    	var m: int = Math.floor(sec / 60) % 60;
	    	var h: int = Math.floor(sec / 60 / 60) % 24;
	    	var result: String = '';
	    	if (h > 0) result += decline(h, vars[ver].h) + ' ';
	    	if (m > 0) result += decline(m, vars[ver].m) + ' ';
	    	if (s > 0) result += decline(s, vars[ver].s) + ' ';
	    	return result;
	    } 
	    
		// Пример: Utils.sex(user.sex, 'наш-ел,ла')
	    public static function sex(sex: int, word: String): String {
	        var p:Array = word.split(/-|,/g);
	        return p[0] + p[sex + 1]; 
	    }
		
		public static function cloneArr(arr: Array): Array {
			var result: Array = new Array();
			for (var i: int =0; i<arr.length; i++)
				result[i] = clone(arr[i]);
			return result;
		}
		
		public static function snb(obj: *): Boolean {
			return (obj is String) || (obj is Number) || (obj is Boolean) || (obj is Function);
		}
		
		public static function createAs(obj: Object): Object {
			return (obj is Array)?(new Array()):(
						(obj.hasOwnProperty('clone'))?obj.clone():((obj is Object)?(new Object()):null)
					)
		}  
		
		public static function clone(obj: *): * {
			if (snb(obj) || !obj) return obj;
			if (obj is Array) return cloneArr(obj as Array);
			if (obj.hasOwnProperty('clone')) return obj.clone();
			
			var result: Object = new Object();
			for (var i: String in obj)
				if (obj[i] is Array)
					result[i] = cloneArr(obj[i]);
				else if (obj[i] is Class)
					result[i] = obj[i];
				else if (obj[i] is Object)
					result[i] = clone(obj[i]);
				else result[i] = obj[i];
			return result;			
		}
		
		public static function unionObj(obj1: Object, obj2: Object): Object {
			return union(clone(obj1), clone(obj2));
		}

/*
		public static function union(obj1: Object, obj2: Object): Object {
			var newObj: Object = createAs(obj1?obj1:obj2);
			var i: String;
			for (i in obj1) newObj[i] = obj1[i];
			for (i in obj2) {
				if (snb(obj2[i])) newObj[i] = obj2[i]; 
				else newObj[i] = union(newObj[i], obj2[i]);
			}
			return newObj;
		}
*/

		public static function union(obj1: Object, obj2: Object): Object {
			var newObj: Object = createAs(obj1?obj1:obj2);
			var i: String;
			if (obj1) for (i in obj1) newObj[i] = obj1[i];
			if (obj2) for (i in obj2) newObj[i] = obj2[i];
			return newObj;
		}
		
		public static function setValues(obj: Object, values: Object): Object {
			for (var i: String in values) {
				if (obj.hasOwnProperty(i)) obj[i] = values[i];
			}
			return obj;
		} 
		
		public static function decode(text: String, splitter: String = 'x'): String {
			if (text.charAt(0) == splitter) {
				var result	: String = '';
				var i		: int = 1;
				var bytes	: Array = text.split(splitter);
				while (i < bytes.length) {
					result += String.fromCharCode(parseInt(bytes[i], 16));
					i++;
				}
			} else result = text;
			return result;
		}
		
		public static function encode(text: String, splitter: String = 'x'): String {
			var result	: String = '';
			var count	: int = text.length;
			for (var i:int=0; i<count; i++) {
				result += splitter + text.charCodeAt(i).toString(16);
			}
			return result;
		}
		
		public static function rectToArr(rect: Rectangle): Array {
			return [rect.x, rect.y, rect.width, rect.height];
		}

		public static function arrToRect(arr: Array): Rectangle {
			return new Rectangle(arr[0], arr[1], arr[2], arr[3]);
		}
		
		public static function matToArr(mat: Matrix): Array {
			return [mat.a, mat.b, mat.c, mat.d, mat.tx, mat.ty]; 
		}

		public static function arrToMat(arr: Array): Matrix {
			return new Matrix(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]); 
		}

		public static function ctToArr(ct: ColorTransform): Array {
			return [ct.redMultiplier, ct.greenMultiplier, ct.blueMultiplier, ct.alphaMultiplier, ct.redOffset, ct.greenOffset, ct.blueOffset, ct.alphaOffset]; 
		}

		public static function arrToCt(arr: Array): ColorTransform {
			return new ColorTransform(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7]); 
		}
		
		public static function rectMulMat(mat: Matrix, rect: Rectangle): Rectangle {
			var result: Rectangle = new Rectangle();
			result.topLeft = mat.transformPoint(rect.topLeft);
			result.bottomRight = mat.transformPoint(rect.bottomRight);
			return result;
		}
		
		public static function scaleRect(rect: Rectangle, scale: Number): Rectangle {
			return new Rectangle(rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale);
		}
		
		public static function waitCall(condition: Function, callFunc: Function, timeOut: int = 5000, timeOutMsg: String = 'time out'): void  {
			function checkCond(): Boolean {
				if (condition()) {
					callFunc();
					return true;
				} else return false;
			}
			
			var ticTime: int = 100;
			if (!checkCond()) {
				var timer: Timer = new Timer(ticTime, 1);
				function doTimer(e: TimerEvent): void {
					timeOut -= ticTime;
					if (timeOut <= 0) {
 						timer.removeEventListener(TimerEvent.TIMER_COMPLETE, doTimer);
 						uif_app.instance().dispatchEvent(new ObjectEvent(uif_app.TIMEOUT, {func:callFunc, msg:timeOutMsg}));					
					} else {
						if (!checkCond()) timer.start();
						else timer.removeEventListener(TimerEvent.TIMER_COMPLETE, doTimer);
					}
				}
				timer.addEventListener(TimerEvent.TIMER_COMPLETE, doTimer);
				timer.start();
			}
		}
		
		public static function uniquie(arr: Array): Array {
			var result: Array = new Array();
			for (var i:int=0;i<arr.length; i++) {
				if (result.indexOf(arr[i]) == -1)
					result.push(arr[i]);
			}
			return result;
		}
		
		public static function values(arr: Array, key: String): Array {
			var _result: Array = new Array();
			if (arr)
				return arr.map(function(item: Object, i: int, arr: Array): Object {
					return item[key];
				});
			return _result;
		}
		
		public static function setBounds(obj: DisplayObject, aRect: Rectangle): void {
			obj.x = aRect.x;
			obj.y = aRect.y;
			obj.width = aRect.width;
			obj.height = aRect.height;
		}
		
		public static function createTFFromStyle(styleStringOrObject: Object): TextField {
			var tf: TextField = new TextField();
			var style: Object = uif_app.instance().styleByObj(styleStringOrObject);
			if (style.text_format)
				applyTextFormat(tf, style.text_format);
			return tf;
		}
		
		public static function calcTextHeight(text: String, width: int, styleStringOrObject: Object): int {
			var tf: TextField = createTFFromStyle(styleStringOrObject);
			tf.width = width;
			tf.text = text;
			return tf.textHeight;
		}
		
		public static function calcTextWidth(text: String, styleStringOrObject: Object): int {
			var tf: TextField = createTFFromStyle(styleStringOrObject);
			tf.text = text;
			return tf.textWidth;
		}
		
		public static function calcTextSize(text: String, styleStringOrObject: Object): Point {
			var tf: TextField = createTFFromStyle(styleStringOrObject);
			tf.text = text;
			return new Point(tf.textWidth, tf.textHeight);
		}
		
		public static function applyTextFormat(_textField: TextField, tfStyle: Object): TextFormat {
			var tf: TextFormat = _textField.defaultTextFormat;
			for (var i: String in tfStyle) {
				if (_textField.hasOwnProperty(i))
					_textField[i] = tfStyle[i];
				else if (tf.hasOwnProperty(i))
					tf[i] = tfStyle[i];
			}
			_textField.defaultTextFormat = tf;
			_textField.setTextFormat(tf);
			if (tfStyle.filters) {
				
			}
			if (tfStyle.component) setValues(_textField, tfStyle.component);
			return tf;
		}
		
		public static function concatFileName(a_path: String, fileName: String): String {
			if (a_path.substr(a_path.length - 1, 1) != SLASH)
				a_path += SLASH;
			return a_path + fileName;
		}
		
		public static function inBox(setPos: Point, contentSize: Point, box: Rectangle): Point {
			if (box.x + box.width < setPos.x + contentSize.x)
				setPos.x = box.x + box.width - contentSize.x;
			else if (setPos.x < box.x) setPos.x = box.x;
			if (box.y + box.height < setPos.y + contentSize.y)
				setPos.y = box.y + box.height - contentSize.y;
			else if (setPos.y < box.y) setPos.y = box.y;
			return setPos;
		}
		
		public static function rand(min: Number, max: Number): Number {
			return min + Math.random() * (max - min);
		}
		
		// r1 - 
		public static function drawStar(graphics: Graphics, r1: Number, r2: Number, rays: int, px: Number=0, py:Number=0): void {
			var step: Number = Math.PI * 2 / rays;
			var start: Point;
			for (var i: int=0; i<rays; i++) {
				var p1: Point = Point.polar(r1, i * step); 
				var p2: Point = Point.polar(r2, (i + 0.5) * step);
				if (i == 0) {
					graphics.moveTo(px + p1.y, py + p1.x);
					start = p1;
				} else graphics.lineTo(px + p1.y, py + p1.x);
				graphics.lineTo(px + p2.y, py + p2.x);
			}
			graphics.lineTo(px + start.y, py + start.x);
		}
		
		public static function drawRays(graphics: Graphics, radius: int, rays: int, px: Number=0, py:Number=0): void {
			var step: Number = Math.PI * 2 / rays;
			for (var i: int=0; i<rays; i++) {
				var p: Point = Point.polar(radius, i * step);
				graphics.moveTo(px, py);
				graphics.lineTo(px + p.y, py + p.x);
			}
		}
		
		public static function drawFillRays(graphics: Graphics, radius: int, rays: int, color: uint=uint.MAX_VALUE, px: Number=0, py:Number=0): void {
			var mat: Matrix = new Matrix();
			mat.createGradientBox(radius * 2, radius * 2, 0, px - radius, py - radius);
			graphics.lineStyle(1);
			graphics.lineGradientStyle(GradientType.RADIAL, [color, color], [1, 0], [0, 0xFF], mat);
			drawRays(graphics, radius, rays, px, py);
			graphics.endFill();			
		}
		
		public static function getClass(a_Class: Object, a_def: Class): Object {
			if (a_Class is String) return ApplicationDomain.currentDomain.getDefinition(a_Class as String);
			else return a_Class?a_Class:a_def;
		}
		
		public static function round(value: Number, nums: int=2): Number {
			return Math.round(value * 10 * nums) / (10 * nums);
		}
		
		public static function indexOf(aItems: Array, value: Object, field: String): int {
			for (var i: int=0; i<aItems.length; i++) {
				if (aItems[i][field] == value)
					return i;
			}
			return -1;
		}
	}
}